/*
 * Create by: Mark Lavrynenko
 * Email:	MarkLavrinenko@gmail.com
 * Project:	  Huffman
*/

#include "FileDataSource.h"
#include "FileDataTarget.h"
#include "HuffmanArchiver.h"
#include "HuffmanOptions.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>
#include <algorithm>
#include <sys/stat.h>
#include <string.h>
#include <math.h>
#include <time.h>

// global variables
time_t time_begin, time_end;

size_t fileSize(char const* filename)
{
	struct stat st;
	assert(0 == stat(filename, &st));
	return st.st_size;
}

static const char* archiveMode = "archive";
static const char* unarchiveMode = "unarchive";
static const size_t maxlen = 11;
static const size_t maxFileNameLength = 255;

void code(const char* inputName, const char* outputName)
{
	time_begin = clock();
	assert(fileSize(inputName) <= MAX_FILE_LEN);
	FileDataSource* ds = new FileDataSource(inputName);
	FileDataTarget* dt = new FileDataTarget(outputName);
	HuffmanArchiver* arch = new HuffmanArchiver();
	arch->archive(ds, dt);
	delete ds;
	delete dt;
	time_end = clock();
}

void uncode(const char* inputName, const char* outputName)
{
	time_begin = clock();
	FileDataSource* ds = new FileDataSource(inputName);
	FileDataTarget* dt = new FileDataTarget(outputName);
	HuffmanArchiver* arch = new HuffmanArchiver();
	arch->unarchive(ds, dt);
	delete ds;
	delete dt;
	time_end = clock();
}

void takeInput()
{
	
	char buf[maxlen];
	do
	{
		printf("Select mode: %s or %s: -> ", archiveMode, unarchiveMode);
		scanf("%s", buf);
	}
	while (0 != strcmp(buf, archiveMode) && 0 != strcmp(buf, unarchiveMode));
	char firstname[maxFileNameLength];
	char secondname[maxFileNameLength];
	printf("Select input file ->");
	scanf("%s", firstname);
	printf("Select output file ->");
	scanf("%s", secondname);
	if (0 == strcmp(buf, archiveMode))
	{
		code(firstname, secondname);
	}
	else
	{
		uncode(firstname, secondname);
	}
}

#ifdef _DEBUG
void test32bitIO()
{
	const int data = -12134213;
	FileDataTarget* dt = new FileDataTarget("tmp");
	dt->putNextInt32(data);
	delete dt;
	DataSource* ds = new FileDataSource("tmp");
	int32_t t = ds->getNextInt32();
	delete ds;
	if (data != t)
		assert(0);
}

void test16bitIO()
{
	const int data = -18123;
	FileDataTarget* dt = new FileDataTarget("tmp");
	dt->putNextInt16(data);
	delete dt;
	DataSource* ds = new FileDataSource("tmp");
	int32_t t = ds->getNextInt16();
	delete ds;
	if (data != t)
		assert(0);
}
#endif

// params are mode, input file, output file
// mode can be archive, unarchive
int main(int argc, char* argv[])
{
#ifdef _DEBUG
	test32bitIO();
	test16bitIO();
#endif
	if (1 == argc)
	{
		takeInput();
	}
	else
	if (4 == argc)
	{
		char* mode = argv[1];
		if (0 == strcmp(archiveMode, mode))
		{
			code(argv[2], argv[3]);
		}
		else
		if (0 == strcmp(unarchiveMode, mode))
		{
			uncode(argv[2], argv[3]);
		}
		else
		{
			printf("Wrong mode\n");
		}
	}
	else
	{
		exit(-1);
	}
#ifdef _DEBUG
	printf("Total time is: %f\n", float(time_end - time_begin) / CLOCKS_PER_SEC);
	system("pause");
#endif
	return 0;
}
